/*
 
 * replace ConceptualDAO and ConceptualBO with the oppropriate BOs and DAOs. Also fix the SQL Statements
 * <p>
 * summary
 *
 * @author      Jeff Jenkins
 * @version     1.0
 *
 */

package edu.byu.isys413.jjenkins.data;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.List;


/**
 *
 *summary
 *
 * <p>
 *
 * summary
 *
 *
 *
 */

public class ConceptualDAO {
    
    private static ConceptualDAO instance = null;
  
    /** Creates a new instance of ConceptualDAO */
    
    private ConceptualDAO() {    
    }
    
    /**
     *This method implements the singleton pattern. It ensures that only one ConceptualDAO exists  
     * @return   Store DAO  
     *  
     */
   
    public static synchronized ConceptualDAO getInstance() {
        
        if (instance == null) {  
            instance = new ConceptualDAO();            
        }       
        return instance;        
    }

    /**
  
     *This method creates a new ConceptualBO with a unique QUID, puts the interest  
     * in cache, and then returns it to the calling metho  
     * 
     * @return   ConceptualBO  
     * @throws  exception  
     */  
    public ConceptualBO create() throws DataException {       
        try {
                    
            String id = GUID.generate();            
            ConceptualBO object = new ConceptualBO();            
            object.setId(id);            
            Cache.getInstance().put(object.getId(), object);           
            return object;            
        } catch (Exception e) {            
            throw new DataException("Could not create GUID", e);           
        }       
    }
    
    
    
    /**  
     *This is the public read statement. It loads an existing recored from the database  
     * <p>  
     * summary  
     *  
     * @param  String id  
     * @return   ConceptualBO  
     * @throws  exception  
     */   
    public synchronized ConceptualBO read(String id) throws DataException {       
        // Checks to see if the item is in cache        
        Cache cache = Cache.getInstance();       
        ConceptualBO object = (ConceptualBO)cache.get(id);        
        try {           
            // Gets connection            
            ConnectionPool connPool = ConnectionPool.getInstance();           
            Connection conn = connPool.get();           
            // If the item is not in cache a connection is checked out and            
            // The item is read from the database.           
            if(object == null){               
                try {                    
                    //reads in object                   
                    object = read(id, conn);                  
                }catch (SQLException e) {                   
                    conn.rollback();                   
                    throw new DataException("Could not retrieve record for id=" + id, e);                    
                }                
            }            
                        
            // connection committs and is returned.            
            conn.commit();            
            connPool.release(conn);          
        } catch (SQLException e) {            
            throw new DataException("Could not retrieve record for id=" + id, e);            
        } catch (DataException e) {            
            throw new DataException("Could not retrieve record for id=" + id, e);            
        } catch (ConnectionPoolException e) {            
            throw new DataException("Could not retrieve record for id=" + id, e);            
        }
        
        // Return object        
        return object;        
    }
    
    
    
    /**
    
     *  This is a package method that is called by the public read (above) or
    
     *  by another DAO.  Either way we already have a connection to the database
    
     *  to use.  The user (controller) code never calls this one directly, since
    
     *  it can't know about Connection objects or SQLExceptions.
    
     *
    
     *  @param  String: id, Connection conn
    
     *  @return ConceptualBO
    
     *  @throws  DataException, SQLException
    
     */
    
    synchronized ConceptualBO read(String id, Connection conn) throws SQLException, DataException {
        
        
        
        
        
        // Checks to see if the item is in cache
        
        Cache cache = Cache.getInstance();
        
        ConceptualBO object = (ConceptualBO)cache.get(id);
        
        
        
        // Quieries that database
        
        if(object == null){
            
            
            
            PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM conceptual WHERE conceptual_id = ?");
            
            pstmt.setString(1, id);
            
            pstmt.execute();
            
            ResultSet rs = pstmt.getResultSet();
            
            
            
            if (rs.next()) {                
                object = new ConceptualBO();                
                object.setId(rs.getString("conceptual_id"));                
                object.setDescription(rs.getString("description"));                
                object.setManufacturer(rs.getString("manufacturer"));               
                object.setAverageCost(rs.getString("averagecost"));   
                object.setAverageCost(rs.getString("productname"));    
                // Sets already in database                
                object.setObjectAlreadyInDB(true);              
                // adds to cache                
                cache.put(object.getId(), object);
               
            }else{
                
                throw new DataException("Object was not found in the database.");
                
            }
            
        }
        
        
        
        
        
        // returns object
        
        return object;
        
    }
    
    
    
    /**
     *
     * This is the public save method.  It is what is called when
     *
     * the user (controller) code wants to save or update an object
     *
     * into the database.
     *
     *
     *
     * @param ConceptualBO object
     *
     * @throws DataExcpetion
     *
     */
    
    public synchronized void save(ConceptualBO object) throws DataException {
        
        try {
            
            
            
            
            
            // retrieve a database connection from the pool
            
            ConnectionPool connPool = ConnectionPool.getInstance();
            
            
            
            Connection conn = connPool.get();
            
            
            
            
            
            try {
                
                
                
                // Saves Interest
                
                save(object, conn);
                
                
                
            }catch (SQLException e) {
                
                conn.rollback();
                
                throw new DataException("Could not save record for" + object.getId(), e);
                
            }
            
            
            
            // connection committs and is returned.
            
            conn.commit();
            
            connPool.release(conn);
            
            
            
            // touch the cache for the object
            
            Cache.getInstance().touch(object.getId());
            
            
            
            
            
            
            
        } catch (DataException e) {
            
            throw new DataException("Could not save record for" + object.getId(), e);
            
        } catch (ConnectionPoolException e) {
            
            throw new DataException("Could not save record for" + object.getId(), e);
            
        } catch (SQLException e) {
            
            throw new DataException("Could not save record for" + object.getId(), e);
            
        }
        
        
        
        
        
    }
    
    
    
    /**
     *
     *  This is a package method that is called by the public save (above) or
     *
     *  by another DAO.  Either way we already have a connection to the database
     *
     *  to use.  The user (controller) code never calls this one directly, since
     *
     *  it can't know about Connection objects or SQLExceptions.
     *
     *
     *
     *  By having other DAOs call this save method (rather than update or
     *
     *  insert below, each DAO in a chained save (like the CustomerDAO calling
     *
     *  MembershipDAO calling InterestDAO save chain) can independently decide
     *
     *  whether to udpate or insert the BO it's saving.  That's why I made
     *
     *  update and insert private rather than package level -- if you call
     *
     *  them directly from another DAO, this DAO can't decide whether it's
     *
     *  object needs to be inserted or updated.
     *
     *
     *
     *  @param ConceptualBO, Connection
     *
     *  @throws SQLException, DataException
     *
     */
    
    synchronized void save(ConceptualBO object, Connection conn) throws SQLException, DataException {
        
        
        
        // check the dirty flag in the object.  if it is dirty,
        
        // run update or insert
        
        if (object.isDirty()) {
            
            if (object.isObjectAlreadyInDB()) {
                
                update(object, conn);
                
            }else{
                
                insert(object, conn);
                
            }
            
            object.setDirty(false);
            
        }
        
        
        
        
        
        
        
    }
    
    
    
    /**
     *
     * This method is really a part of save(bo, conn) above.  It could be
     *
     * embedded directly in it, but I've separated it into it's own method
     *
     * to isolate the SQL udpate statement and make it more readable.  But
     *
     * logically, it's really just a part of save.
     *
     *
     *
     * @paramConceptualBO object
     *
     */
    
    private synchronized void update(ConceptualBO object, Connection conn) throws SQLException, DataException {
        
        
        
        PreparedStatement pstmt = conn.prepareStatement("UPDATE conceptual SET productname = ?, description = ?, manufacturer = ?, averagecost = ? WHERE conceptual_id = ?");
        pstmt.setString(1, object.getProductName());
        pstmt.setString(2, object.getDescription());
        pstmt.setString(3, object.getManufacturer());
        pstmt.setString(4, object.getAverageCost());
        pstmt.setString(5, object.getId());     
        pstmt.execute();     
    }
    
    
    
    /**
     *
     * This method is really a part of save(bo, conn) above.  It could be
     *
     * embedded directly in it, but I've separated it into it's own method
     *
     * to isolate the SQL insert statement and make it more readable.  But
     *
     * logically, it's really just a part of save.
     *
     *
     *
     * @paramConceptualBO object
     *
     */
    
    private synchronized void insert(ConceptualBO object, Connection conn) throws SQLException, DataException {
        
        
        
        // Creates prepared statemetn
        
        PreparedStatement pstmt = conn.prepareStatement("INSERT INTO conceptual VALUES(?, ?, ?, ?, ?)");
        pstmt.setString(1, object.getId());  
        pstmt.setString(2, object.getProductName());
        pstmt.setString(3, object.getDescription());
        pstmt.setString(4, object.getManufacturer());
        pstmt.setString(5, object.getAverageCost());
        pstmt.execute();  
        //Sets already in database true
        
        object.setObjectAlreadyInDB(true);
    }
    
    
    
    
    
    /**
  
     * This method deletes an object from the database
  
     *
  
     * @param ConceptualBO object
  
     */
    
    
    
    public synchronized void delete(ConceptualBO objects)throws DataException{
       /* 
        // Creates prepared statemetn
        
        PreparedStatement pstmt = conn.prepareStatement("Delete From store WHERE id = ?");
        
        pstmt.setString(1, object.getId());
        
        
        
        //Executes prepated statement
        
        pstmt.execute();
        
        
        
        // or
        
        //throw new DataException("You can not delete a ConceptualBO");
        */
    }
    
    
    
    /**
   
     * This method reads all objects from the database
   
     *
   
     * @param ConceptualBO object
   
     */
    
    public synchronized List<ConceptualBO> readAll() throws SQLException, DataException {
        
        
        
        List list = new LinkedList();
        
        
        
        try {
            
            
            
            // Gets connection
            
            ConnectionPool connPool = ConnectionPool.getInstance();
            
            Connection conn = connPool.get();
            
            
            
            // prepares statemnt
            
            
            
            PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM conceptual");
            
            pstmt.execute();
            
            ResultSet rs = pstmt.getResultSet();
            
            
            
            
            
            while(rs.next()){
                
                String line_id = rs.getString("conceptual_id");
                
                list.add(read(line_id, conn));
                
            }
            
            
            
            // connection committs and is returned.
            
            conn.commit();
            
            connPool.release(conn);
            
            
            
            
            
            
            
        } catch (SQLException e) {
            
            throw new DataException("Could not retrieve record", e);
            
        } catch (DataException e) {
            
            throw new DataException("Could not retrieve record", e);
            
        } catch (ConnectionPoolException e) {
            
            throw new DataException("Could not retrieve record", e);
            
        }
        
        
        
        
        
        
        
        return list;
        
    }
    
    
    
}


